import * as THREE from 'three';
import { BaseDemo } from './BaseDemo';
import { Emitter, GravityForceField, ParticleSystem, Tween } from '../index';
import { getSPEMat } from '../util';
import { GroundConstraint } from '../Constaint';
import GUI from "three/examples/jsm/libs/lil-gui.module.min.js";

export class FountainDemo extends BaseDemo {
    private emitter?: Emitter;
    private gravity?: GravityForceField;
    private ground?: GroundConstraint;
    private alphaTween?: Tween<number>;

    constructor(scene: THREE.Scene) {
        super('喷泉效果', '水柱喷泉效果，展示连续发射、重力和地面碰撞', scene);
    }

    init(): void {
        // 创建水粒子材质
        const material = getSPEMat({
            color: new THREE.Color(0x4ec8f0),
            size: 2,
            sizeAttenuation: false,
            vertexColors: false,
            depthTest: true,
            depthWrite: false,
            blending: THREE.NormalBlending,
            transparent: true,
            opacity: 0.7,
        });

        // 创建发射器 - 向上喷射
        this.emitter = new Emitter({
            origin: new THREE.Vector3(0, 0, 0),
            rate: 500,
            life: 4,
            emitterLife: 100, // 持续喷射
            volecity: new THREE.Vector3(0, 25, 0),
            randomVelocity: {
                direction: new THREE.Vector3(0, 1, 0),
                coneAngle: 0.3, // 小角度锥形
                speedMin: 20,
                speedMax: 30,
            },
            angle: 0,
            size: 1,
            shape: 'point',
            material: material,
            maxCount: 2000,
        });

        // 重力场
        this.gravity = new GravityForceField(new THREE.Vector3(0, -9.8, 0));

        // 地面约束
        this.ground = new GroundConstraint(0.1, 0);

        // 透明度变化：随着生命周期逐渐透明
        this.alphaTween = new Tween(
            [0, 2, 4],
            [0.8, 0.5, 0.1],
            'alpha'
        );

        // 创建粒子系统
        this.particleSystem = new ParticleSystem(
            [this.emitter],
            [this.gravity],
            [this.alphaTween],
            [this.ground]
        );
    }

    protected createControls(folder: GUI): void {
        if (!this.emitter || !this.gravity) return;

        const controls = {
            power: 25,
            rate: 500,
            coneAngle: 0.3,
            gravity: -9.8,
            restitution: 0.1,
            particleLife: 4,
        };

        folder.add(controls, 'power', 10, 50)
            .name('喷射力度')
            .onChange((value: number) => {
                if (this.emitter) {
                    this.emitter.initialVelocity.y = value;
                    this.emitter.randomVelocity.speedMin = value * 0.8;
                    this.emitter.randomVelocity.speedMax = value * 1.2;
                }
            });

        folder.add(controls, 'rate', 100, 1000)
            .name('发射速率')
            .onChange((value: number) => {
                if (this.emitter) {
                    this.emitter.rate = value;
                }
            });

        folder.add(controls, 'coneAngle', 0, 1)
            .name('喷射角度')
            .onChange((value: number) => {
                if (this.emitter) {
                    this.emitter.randomVelocity.coneAngle = value;
                }
            });

        folder.add(controls, 'gravity', -20, 0)
            .name('重力强度')
            .onChange((value: number) => {
                if (this.gravity) {
                    this.gravity.gravity.y = value;
                }
            });

        folder.add(controls, 'restitution', 0, 1)
            .name('反弹系数')
            .onChange((value: number) => {
                if (this.ground) {
                    this.ground.restitution = value;
                }
            });

        folder.add(controls, 'particleLife', 1, 10)
            .name('粒子生命')
            .onChange((value: number) => {
                if (this.emitter) {
                    this.emitter.life = value;
                }
            });

        folder.open();
    }
}